﻿using System;
using HK.Core.Common;
using HK.Core.Load.Protocol.Data;
using HK.Core.Load.Protocol.Signal;
using HK.Core.Utils;
using UnityEngine;
using UnityEngine.U2D;
using Object = UnityEngine.Object;

namespace HK.Core.Load.Data
{
    /// <summary>
    /// 资产信息
    /// </summary>
    public abstract class AssetInfo : AssetBase, IAssetInfo
    {
        
        /// <summary>
        /// AssetKey
        /// </summary>
        public string AssetKey => Key;

        /// <summary>
        /// 文件后缀
        /// </summary>
        public string Extension { get; private set; } = null;

        /// <summary>
        /// 完整Key
        /// <para>* 包含后缀名</para>
        /// </summary>
        public string FullKey => string.IsNullOrEmpty(Extension) ? AssetKey : $"{AssetKey}.{Extension}";

        /// <summary>
        /// 加载资产类型
        /// </summary>
        public override LoadAssetType LoadType => LoadAssetType.Asset;
        
        /// <summary>
        /// 资产类型
        /// </summary>
        public AssetFileType AssetType { get; private set; } = AssetFileType.Unknown;

        /// <summary>
        /// AbId
        /// </summary>
        public string AbId { get; private set; } = null;
        
#region Atlas

        /// <summary>
        /// 图集标志位
        /// </summary>
        public bool IsAtlas => AssetFileType.Atlas == AssetType;

        /// <summary>
        /// Include in build
        /// <para>* 当且仅当图集时有效</para>
        /// </summary>
        public bool IncludeInBuild { get; protected set; } = true;

#endregion
        
        /// <summary>
        /// 设定信息
        /// </summary>
        /// <param name="iAssetKey">AssetKey</param>
        /// <param name="iOptions">选项</param>
        /// <param name="iAbId">Ab Id</param>
        /// <param name="iAsync">异步标志位</param>
        /// <param name="iCoolTime">倒计时冷却时间(默认 : 30秒)</param>
        public void SetInfo(string iAssetKey, int iOptions, string iAbId = null, bool iAsync = false, float iCoolTime = Const.DefaultCoolTime) 
        {
            // 设定信息
            SetInfo(iAssetKey, iOptions, SignalGroupType.AssetBundle, iAsync, iCoolTime);
                    
            // AbId
            AbId = iAbId;
            // 设置资产文件类型
            AssetType = UtilsIo.GetAssetFileTypeByAssetKey(iAssetKey, out var oExtension);
            if (!string.IsNullOrEmpty(oExtension))
            {
                Extension = oExtension;
            }
        }

        /// <summary>
        /// 清空
        /// </summary>
        public override void Clear()
        {
            base.Clear();

            Extension = null;
            AssetType = AssetFileType.Unknown;
            IncludeInBuild = true;
        }
    }

    /// <summary>
    /// 未知Asset类型异常
    /// </summary>
    public class UnknownAssetTypeException : Exception
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="iMessage"></param>
        public UnknownAssetTypeException(string iMessage) : base(iMessage) {}
    }

    /// <summary>
    /// 资产信息
    /// </summary>
    /// <typeparam name="TAsset">资产类型</typeparam>
    public class AssetInfo<TAsset> : AssetInfo, IAssetInfo<TAsset>
        where TAsset : UnityEngine.Object
    {
        
#region Asset

        /// <summary>
        /// 资产类型
        /// </summary>
        public TAsset Asset { get; private set; } = default(TAsset);

        /// <summary>
        /// 设定Asset
        /// </summary>
        /// <param name="iAsset">Asset</param>
        /// <param name="iFrom">加载来源</param>
        /// <param name="iIncludeInBuild">Include In Build</param>
        public void SetAsset(TAsset iAsset, LoadFrom iFrom, bool iIncludeInBuild = false)
        {
            Asset = iAsset;
            From = iFrom;
            IncludeInBuild = iIncludeInBuild;
        }

#endregion

        /// <summary>
        /// 清空
        /// </summary>
        public override void Clear()
        {
            base.Clear();

            Asset = default(TAsset);
        }
        
        /// <summary>
        /// 释放自身
        /// </summary>
        /// <returns>true:释放成功; false:释放失败;</returns>
        protected override bool ReleaseSelf()
        {
            if (default(TAsset) != Asset)
            {
                if(FromResource)
                {
                    // 若是Sprite，则虚先释放Sprite对应的Texture
                    if (Asset is Sprite sprite)
                    {
                        Resources.UnloadAsset(sprite.texture); 
                        Resources.UnloadAsset(sprite); 
                    }
                    else if (Asset is Texture ||
                             Asset is Mesh ||
                             Asset is Material ||
                             Asset is Shader ||
                             Asset is TextAsset ||
                             Asset is SpriteAtlas ||
                             Asset is ScriptableObject)
                    {
                        Resources.UnloadAsset(Asset);
                    }
                    else if (Asset is GameObject)
                    {
                        Object.DestroyImmediate(Asset, true);
                    }
                    else
                    {
                        throw new UnknownAssetTypeException($"Unknown Asset Type!(Type:{typeof(TAsset).Name})");
                    }
                }
                Asset = default(TAsset);
                return true;
            }

            return false;
        }
        
    }
}